package sparrowGui.utils
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Shape;
	import flash.text.TextField;
	import flash.utils.describeType;
	
	import sparrowGui.SparrowGUI;
	
	/**
	 * 工具包
	 * @author Pelephone
	 */
	public class SparrowUtil
	{
		/// 字符串处理 ///////////
		/**
		 * 转语言包对象字符串缓存对象
		 */
		private static var cacheLangObj:Object;
		
		/**
		 * 通过变量字符设置语言包
		 * 例如{aa}对{bb}说asdf,通过obj的aa,bb属性转成 A对B说asdf
		 */
		public static function langByObj(langStr:String,obj:Object):String
		{
			cacheLangObj = obj;
			var exp:RegExp = /{\w+}/g;
			var reStr:String = langStr.replace(exp, langToken);
			cacheLangObj = null;
			return reStr;
		}
		
		/**
		 * 解析字符
		 */
		private static function langToken(...args):String
		{
			var attr:String = args[0];
			attr = attr.substr(1,attr.length-2);
			var valStr:String = cacheLangObj.hasOwnProperty(attr)?String(cacheLangObj[attr]):"";
			return valStr;
		}
		
		/**
		 * 遍历复制动态对象的动态属性到reObj对象上
		 * @param reObj
		 * @param vars
		 * @param ignoreProps
		 */
		public static function copyDynamicCopy(reObj:Object,dynamicVars:Object,ignoreProps:Array=null):*
		{
			for (var propName:String in dynamicVars)
			{
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				setObjectValue(reObj,propName,dynamicVars[propName]);
			}
			return reObj;
		}
		
		/**
		 * 复制对象属性
		 * @param Jobj		要解析的Object对象
		 * @param voClz		要转成的vo对象的类名
		 */
		public static function copyObject(reObj:Object,vars:Object,ignoreProps:Array=null):*
		{
			var desc:XML = describeType( vars );
			// 设置 obj 的每个属性 prop
			for each(var prop:XML in desc.variable)
			{
				var propName:String = prop.@name;			// 变量名
				var propType:String = prop.@type;			// 变量类型
				
				// 忽略了
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				setObjectValue(reObj,propName,vars[propName]);
			}
			// 设置 obj 的每个属性 set/get
			for each(prop in desc.accessor)
			{
				propName = prop.@name;			// 变量名
				propType = prop.@type;			// 变量类型
				
				// 忽略了
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				setObjectValue(reObj,propName,vars[propName]);
			}
			copyDynamicCopy(reObj,vars,ignoreProps);
			
			return reObj;
		}
		
		/**
		 * 通过属性名,和值,设置对象属性
		 */
		private static function setObjectValue(obj:Object,propName:String,val:*):void
		{
			try
			{
				if(!obj.hasOwnProperty(propName)) return;
				obj[propName] = val;
			} 
			catch(error:Error) 
			{
				trace("设置",obj,"的",propName,"属性有问题!");
				throw error;
			}
		}
		
		
		/**
		 * 清理断开对象里的所有引用对象,一般是要删除某对象时用此方法
		 * @param obj
		 * @return 
		 */		
		public static function killObject(reObj:Object,ignoreProps:Array=null):*
		{
			var desc:XML = describeType( reObj );
			// 设置 obj 的每个属性 prop
			for each(var prop:XML in desc.variable)
			{
				var propName:String = prop.@name;			// 变量名
				
				// 忽略了
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				
				reObj[propName] = null;
			}
			// 设置 obj 的每个属性 set/get
			for each(prop in desc.accessor)
			{
				propName = prop.@name;			// 变量名
				var access:String = prop.@access;
				
				// 忽略了
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				if(access=="readonly") continue;
				
				reObj[propName] =null;
			}
			// 如果是动态类就设置动态属性
			for (propName in reObj)
			{
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				reObj[propName] = null;
			}
			return reObj;
		}
		
		/**
		 * 设置按钮中的文字
		 * @param btn		目标按钮
		 * @param text		新的文字, 当为 null 时, 不设置新文本(仅返回原先的文本)
		 * @param isHtml	是否是html文本
		 * @return			返回新的文本内容
		 */
		static public function setButtonText(btn:DisplayObject, text:String=null, isHtml:Boolean = false):String
		{
			//
			var prevText:String = "";
			text = text || "";
			
			//
			var list:Array = [ btn["upState"], btn["downState"], btn["overState"], btn["hitTestState"],btn];
			if(btn.hasOwnProperty("selectState")) list.push(btn["selectState"]);
			if(btn.hasOwnProperty("disableState")) list.push(btn["disableState"]);
			for each(var disp:DisplayObject in list)
			{
				var tf:TextField = disp as TextField;
				if(tf == null){
					var cont:DisplayObjectContainer = disp as DisplayObjectContainer;
					if(cont) tf = findChild(cont, TextField) as TextField;
				}
				if(tf){
					if(isHtml){
						tf.htmlText = text;
					}else{
						tf.text = text;
					}
					prevText = tf.text;
				} 
			}
			
			//
			return text || prevText;
		}
		
		/**
		 * 替换 newObj 成为 existObj, 并按它的位置对齐, 然后把 existObj 变为 newObj 的孩子, 并使名字相同
		 */
		static public function replaceDP(newObj:DisplayObjectContainer, existObj:DisplayObject):void{
			
			existObj.parent.addChild(newObj);
			existObj.parent.swapChildren(newObj, existObj);
			
			var x:int = existObj.x;
			var y:int = existObj.y;
			var w:int = existObj.width;
			var h:int = existObj.height;
			
			newObj.addChild(existObj);
			existObj.x = 0;
			existObj.y = 0;
			
			newObj.x = x;
			newObj.y = y;
			newObj.width = w;
			newObj.height = h;
			newObj.name = existObj.name;
		}
		
		/**
		 * 返回指定类型的孩子
		 * @param node		被寻找的父节点
		 * @param tClass	子类孩子的过滤, 如果为 null, 则返回第一个孩子
		 */
		static public function findChild(node:DisplayObjectContainer, tClass:Class=null):DisplayObject
		{
			if(tClass == null) tClass = DisplayObject;
			for(var i:int=0; i<node.numChildren; i++){
				var disp:DisplayObject = node.getChildAt(i);
				if(disp is tClass) return disp;
			}
			return null;
		}
		
		
		/**
		 * 清除容器里面的所有显示对象
		 * @param s
		 */		
		static public function clearDisp(s:DisplayObjectContainer):void
		{
			if(s) while(s.numChildren) s.removeChildAt(0);
		}
		
		
		/**
		 * 将容器内的显示单位排列
		 * @param dispArr		要排列的显示容器组
		 * @param spacing		间距
		 * @param hvArrange		排列方式，0为横排，1为竖排
		 */		
		public static function arrangeDisp(dispArr:Array,spacing:int=0,direction:String="vertical"):void
		{
			var xyArg:String = (direction==SparrowGUI.VERTICAL)?"y":"x";
			var whArg:String = (direction==SparrowGUI.VERTICAL)?"height":"width";
			var tmpXY:int = 0;
			for(var i:int;i<dispArr.length;i++){
				var dp:DisplayObject = dispArr[i] as DisplayObject;
				dp[xyArg] = tmpXY;
				tmpXY = tmpXY + dp[whArg] + spacing;
			}
		}
		
		/**
		 * 按行列二维排列容器里的项,先从左到右，再从上到下排
		 * @param disp
		 * @param perColNum		每列有x项,如果为0则一排,横排
		 * @param colWidth		每列的列宽,如果为0则按item的宽度自动排列,即列宽==项宽
		 * @param rowHeight		每列的列高度,如果为0则按item的高度自动向下排列,即行高==项高
		 */
		public static function arrangeDispRC(dispArr:Object,perColNum:int=1,
											 colWidth:int=0,rowHeight:int=0,spacing:int=0):void
		{
			var tmpY:int=0,tmpX:int=0;
			var i:int = 0;
			for each (var dp:Object in dispArr) 
			{
				if(i && !(i%perColNum) && perColNum!=0){
					tmpY = tmpY + spacing + (rowHeight?rowHeight:dp.height);
					tmpX = 0;
				}
				dp.x = tmpX;
				tmpX = tmpX + (colWidth || dp.width) + spacing;
				dp.y = tmpY;
				i++;
			}
			
/*			for(var i:int;i<dispArr.length;i++){
				var dp:DisplayObject = dispArr[i] as DisplayObject;
				if(i && !(i%perColNum) && perColNum!=0){
					tmpY = tmpY + spacing + (rowHeight?rowHeight:dp.height);
					tmpX = 0;
				}
				dp.x = tmpX;
				tmpX = tmpX + (colWidth || dp.width) + spacing;
				dp.y = tmpY;
			}*/
		}
		
		/**
		 * 根据比率排列容器里的显示对象
		 * @param disp	要排列的对象
		 * @param width	排列后的总宽度
		 * @param odds	比率
		 */
		public static function arrangDispByOdds(disp:DisplayObjectContainer,width:int,odds:Array,isWidth:Boolean=false):void
		{
			var tmpx:int=0;
			for(var i:int=0;i<disp.numChildren;i++){
				var dp:DisplayObject = disp.getChildAt(i);
				if(isWidth) dp.width = Math.round(odds[i]*width);
				dp.x = tmpx;
				tmpx += Math.round(odds[i]*width);
			}
		}
		
		/**
		 * 画箭头
		 * @param dr	方向0:下,1:上,2:左,3:右
		 * @param dis	大小
		 */		
		public static function drawArrow(dr:int=0,dis:int=11):Shape
		{
			var shap:Shape = new Shape();
			shap.graphics.beginFill(0x666666);
			if(dr==0){	//指向下
				shap.graphics.moveTo(0,0);
				shap.graphics.lineTo(dis,0);
				shap.graphics.lineTo(dis/2,dis);
			}
			else if(dr==1){	//指向上
				shap.graphics.moveTo(dis/2,0);
				shap.graphics.lineTo(0,dis);
				shap.graphics.lineTo(dis,dis);
			}
			else if(dr==2){	//指向左
				shap.graphics.moveTo(dis,0);
				shap.graphics.lineTo(dis,dis);
				shap.graphics.lineTo(0,dis/2);
			}
			else if(dr==3){	//指向右
				shap.graphics.moveTo(0,0);
				shap.graphics.lineTo(0,dis);
				shap.graphics.lineTo(dis,dis/2);
			}
			shap.graphics.endFill();
			return shap;
		}
		
		
		
		////////////////////////////////////////////////
		// xml解析部分
		///////////////////////////////////////////////
		
		/**
		 * 将xml上的属性信息解析到单个对象
		 * @param xml			要解析的xml
		 * @param obj	  		要将xml解析到对象类
		 * @param ignoreProps	忽略的属性名列表
		 * @return 
		 */		
		static public function parseXMLItem(xml:Object, obj:Object, ignoreProps:Array=null):*
		{
			if(xml) xml = xml[0];		// 调整到子结点
			if(xml==null || !XML(xml).length()) return;
			
			var desc:XMLList = describeType( obj )["variable"];
			// 设置 obj 的每个属性 prop
			for each(var prop:XML in desc)
			{
				var propName:String = prop.@name;			// 变量名
				var propType:String = prop.@type;			// 变量类型
				
				// 忽略了
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				
				var list:XMLList = xml.attribute(propName);
				// 先判断是否有此属性,没有再判断是否有些节点
				if(!list.length()) list = xml.child(propName);
				// 如果无节点或者节点是数组则不解析
				if(!list.length() || list.length()>1) continue;
				
				switch(propType)
				{
					// 基本类型
					case "Boolean":
						obj[propName] = Boolean(int(list))
						break;
					case "int":
					case "uint":
					case "String":
					case "Number":
					{
						obj[propName] = list;		// 变量名 和 xml节点名 必须相同 
					}
						break;
				}
			}
			return obj;
		}
		
		/**
		 * 解析xml并生成新的对象返回
		 * @param xml		  要解析的xml
		 * @param tClass	  要将xml解析生成的类
		 * @param ignoreProps 忽略的属性名列表
		 * @return 
		 */		
		static public function parseXMLByClass(xml:Object, tClass:Class, ignoreProps:Array=null):*
		{
			if(xml) xml = xml[0];		// 调整到子结点
			if(xml==null || !XML(xml).length()) return;
			var obj:Object = new (tClass)();
			parseXMLItem(xml,obj,ignoreProps);
			return obj;
		}
		
		/**
		 * 将xml解析到数组对象里面,不包括子节点
		 * @param xmlList
		 * @param defaultClass
		 * @param ignoreProps
		 * @return 
		 */		
		static public function parseXMLList(xmlList:XMLList, defaultClass:Class, ignoreProps:Array=null):Array
		{
			if(xmlList==null || defaultClass==null) return null;
			var arr:Array = new Array;
			for each(var xml:XML in xmlList)
			{
				var obj:Object = parseXMLByClass(xml, defaultClass, ignoreProps);
				arr.push( obj ); 
			}
			return arr;
		}
	}
}